#ifndef __CONFIG_H__

#define __CONFIG_H__

#include <string.h>

namespace config {

inline void read(int addr, int length, void* content) {
    int end_addr = addr + length;
    uint8_t* data = (uint8_t*)content;
    while(addr != end_addr) {
        *data = EEPROM.read(addr);
        ++addr;
        ++data;
    }
}

inline void write(int addr, int length, const void* content) {
    int end_addr = addr + length;
    uint8_t* data = (uint8_t*)content;
    while(addr != end_addr) {
        EEPROM.write(addr, *data);
        ++addr;
        ++data;
    }
}

inline bool match(int addr, int length, const void*content) {
    int end_addr = addr + length;
    uint8_t* data = (uint8_t*)content;
    while(addr != end_addr) {
        if (EEPROM.read(addr) != *data) {
            return false;
        }
        ++addr;
        ++data;
    }
}

    static int available_address = 0;

class Entry {
    const char* marker;
    int addr;
    int length;
    void *instance;

public:
    template<class C>
    inline Entry(const char* marker, C* instance) {
        this->marker = marker;
        length = sizeof(C);
        addr = available_address;
        available_address += sizeof(C) + strlen(marker);
        this->instance = instance;
    }

    inline void store() {
        int marker_length = strlen(marker);
        write(addr, strlen(marker), marker);
        write(addr + marker_length, length, instance);
    }

    inline void load() {
        read(addr + strlen(marker), length, instance);
    }

    inline void init() {
        if (!match(addr, strlen(marker), marker)) {
            store();
        } else {
            load();
        }
    }
};

}

#endif // __CONFIG_H__
